#include <iostream>
#include <unordered_map>
#include <unistd.h>
#include <functional>
#include <vector>
#include <memory>

namespace wyl
{
    using TaskFunc = std::function<void()>;   // 任务处理函数
    using ReleasFunc = std::function<void()>; // 移除定时器函数

    // 定时任务
    class TimeTask
    {
    private:
        uint64_t _id;    // 定时任务的id
        uint32_t _delay; // 推迟的秒数
        TaskFunc _task_cb;
        ReleasFunc _releas_cb;
        bool _isCancle;

    public:
        TimeTask(uint64_t id, uint32_t delay, const TaskFunc &cb) : _id(id), _delay(delay), _task_cb(cb),_isCancle(false) {}

        // 获取定时任务的延迟时间
        uint32_t GetDelayTime() { return _delay; }

        // 设置定时器的移除任务
        void SetReleas(const ReleasFunc &cb) { _releas_cb = cb; }

        //取消定时任务
        void Cancle(){ _isCancle = true;}

        ~TimeTask()
        {
            if(_isCancle == false)
                _task_cb();   // 处理定时器任务
            _releas_cb(); // 销毁定时器任务
        }
    };

    // 时间轮
    class TimerWheel
    {
    private:
        using WeakTask = std::weak_ptr<TimeTask>; // 用weak_ptr是为了防止shared_ptr管理原始对象时出现引用计数重置的情况
        using SharedTask = std::shared_ptr<TimeTask>;
        int _tick;                                     // 时间轮秒表
        int _capacity;                                 // 时间轮的容量
        std::vector<std::vector<SharedTask>> _wheel;    // 时间轮
        std::unordered_map<uint64_t, WeakTask> _timers; // 定时任务ID和初始任务的映射

    private:
        void RemoveTimer(uint64_t id) // 移除定时器任务对象
        {
            auto it = _timers.find(id);
            if (it != _timers.end())
            {
                _timers.erase(it);
            }
        }

    public:
        TimerWheel() : _tick(0), _capacity(60), _wheel(60) {} //_wheel(60)相当于数组开60个元素

        // 添加定时器任务
        void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
        {
            SharedTask sptr(new TimeTask(id, delay, cb));        // 创建一个定时任务对象
            sptr->SetReleas(std::bind(&TimerWheel::RemoveTimer, this, id)); // 设置wptr的移除定时任务处理函数
            int pos = (_tick + delay) % _capacity;                          // 秒表位置，环形结构
            _wheel[pos].push_back(sptr);                                    // 把任务加进时间轮
            _timers[id] = WeakTask(sptr);                                  // 建立智能指针和i任务d的映射关系
            
        }

        // 刷新定时任务
        void TimerRefresh(uint64_t id)
        {
            // 找到id对应的智能指针
            auto it = _timers.find(id);
            if (it == _timers.end())
            {
                std::cout << "没有找到定时任务，无法刷新 " << std::endl;
                return;
            }
            // 通过weak_ptr构造出一个shared_ptr对象
            SharedTask sptr = it->second.lock();
            int delay = sptr->GetDelayTime(); // 获取延迟时间

            // 加入到时间轮中
            int pos = (_tick + delay) % _capacity;
            _wheel[pos].push_back(sptr);
            std::cout << "刷新定时任务" << pos << std::endl;
        }

        //取消定时任务
        void TimerCancle(uint64_t id)
        {
            // 找到id对应的智能指针
            auto it = _timers.find(id);
            if (it == _timers.end())
            {
                return;
            }
            SharedTask sptr = it->second.lock(); 
            sptr->Cancle();
        }

        // 时间轮运行
        void RunTimerWheel()
        {
            _tick = (_tick + 1) % _capacity;
            _wheel[_tick].clear();
        }
    };

    class Task
    {
    public:
        Task() { std::cout << "Task() " << std::endl; }
        ~Task() { std::cout << "~Task()" << std::endl; }
    };

    void Delete(Task *t)
    {
        delete t;
    }

    void Test1()
    {
        TimerWheel wheel;
        Task *t = new Task();

        wheel.TimerAdd(888, 5, std::bind(Delete, t));
        for (int i = 1; i <= 5; i++)
        {
            wheel.TimerRefresh(888);
            wheel.RunTimerWheel();
            std::cout << "任务刷新，还有5s后释放" << std::endl;
            sleep(1);
        }
        
        wheel.TimerCancle(888);
        while(1)
        {
            sleep(1);
            std::cout << "---------------------------" << std::endl;
            wheel.RunTimerWheel();
        }
    }
}

int main()
{
    wyl::Test1();
    return 0;
}